package com.atguigu.spzx.user.service.impl;

import cn.hutool.core.net.Ipv4Util;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import com.atguigu.spzx.common.handler.exception.SpzxException;
import com.atguigu.spzx.common.handler.interceptor.SpzxServiceAuthInterceptor;
import com.atguigu.spzx.common.handler.util.IpUtil;
import com.atguigu.spzx.common.util.utils.RegexValidateUtils;
import com.atguigu.spzx.model.dto.h5.UserRegisterDto;
import com.atguigu.spzx.model.entity.h5.UserInfo;
import com.atguigu.spzx.model.result.ResultCodeEnum;
import com.atguigu.spzx.model.vo.h5.UserInfoVo;
import com.atguigu.spzx.user.mapper.UserMapper;
import com.atguigu.spzx.user.service.UserInfoService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
public class UserInfoServiceImpl extends ServiceImpl<UserMapper, UserInfo> implements UserInfoService {
    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Resource
    RedisTemplate redisTemplate;
    @Override
    public void register(UserRegisterDto userRegisterDto) {
        //1、校验参数
        String username = userRegisterDto.getUsername();
        String password = userRegisterDto.getPassword();
        String nickName = userRegisterDto.getNickName();
        String code = userRegisterDto.getCode();
        if(StringUtils.isEmpty(username)||
                StringUtils.isEmpty(password)||
                StringUtils.isEmpty(nickName)||
                StringUtils.isEmpty(code)||
                !RegexValidateUtils.checkCellphone(username)){
            throw new SpzxException(ResultCodeEnum.REGISTE_PARAMS_ERROR,null);

        }
        //2、验证码校验
        String cacheCode = stringRedisTemplate.opsForValue().get("spzx:code:regist:" + username);
        if(StringUtils.isEmpty(cacheCode) || !cacheCode.equals(code)){
            throw new SpzxException(ResultCodeEnum.REGISTE_PARAMS_ERROR,null);
        }
        //3、重复注册校验: 使用本次注册的手机号去数据库查询userinfo表中是否存在记录
        long count = this.count(Wrappers.lambdaQuery(UserInfo.class)
                .eq(UserInfo::getUsername, username));
        if(count>0){
            throw new SpzxException(ResultCodeEnum.REGISTE_MOBILE_EXISTS_ERROR,null);
        }
        //4、密码加密 保存到数据库
        UserInfo userInfo = new UserInfo();
        BeanUtils.copyProperties(userRegisterDto , userInfo);
        //生成盐
        String salt = RandomUtil.randomString(6);
        userInfo.setSalt(salt);
        //密码结合盐加密：  先对密码加密 + 盐 再加密
        String encodedPwd = DigestUtils.md5DigestAsHex((DigestUtils.md5DigestAsHex(userInfo.getPassword().getBytes()) + salt).getBytes());
        userInfo.setPassword(encodedPwd);
        userInfo.setStatus(1);
        userInfo.setAvatar("https://img.alicdn.com/imgextra/i4/O1CN01zJMPkf1vvDtzGGQKW_!!6000000006234-2-tps-144-144.png");

        this.save(userInfo);
        //5、清空redis缓存
        stringRedisTemplate.delete("spzx:code:regist:" + username);

    }


    @Override
    public String login(UserInfo userInfo) {
        //1、参数校验
        String username = userInfo.getUsername();
        String password = userInfo.getPassword();
        if(StringUtils.isEmpty(username)||
                StringUtils.isEmpty(password)){
            throw new SpzxException(ResultCodeEnum.LOGIN_PARAMS_ERROR,null);
        }
        //2、根据账号查询用户信息
        UserInfo dbUserInfo = this.getOne(Wrappers.lambdaQuery(UserInfo.class)
                .eq(UserInfo::getUsername, username));
        if(dbUserInfo==null){
            throw new SpzxException(ResultCodeEnum.LOGIN_USERNAME_ERROR,null);
        }
        //用户状态校验
        if(dbUserInfo.getStatus().intValue() != 1){
            throw new SpzxException(ResultCodeEnum.LOGIN_USER_STATUS_ERROR,null);
        }
        //3、账号存在，校验密码
        //使用明文密码 和盐 采用注册的加密方式加密 和数据库密文比较
        String encodedPwd = DigestUtils.md5DigestAsHex((DigestUtils
                .md5DigestAsHex(password.getBytes())
                + dbUserInfo.getSalt()).getBytes());
        if(!encodedPwd.equals(dbUserInfo.getPassword())){
            throw new SpzxException(ResultCodeEnum.LOGIN_PASSWORD_ERROR,null);
        }
        //密码正确
        //4、生成token 缓存到redis中
        String token = IdUtil.getSnowflake(1,1).nextIdStr();
        dbUserInfo.setPassword(null);
        dbUserInfo.setSalt(null);
        redisTemplate.opsForValue().set("spzx:user:login:"+token , dbUserInfo,7, TimeUnit.DAYS);

        //登录成功：更新用户最后一次登录的时间 和 ip地址
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String ipAddress = IpUtil.getIpAddress(request);
        userInfo.setLastLoginIp(ipAddress);
        userInfo.setLastLoginTime(new Date());
        userInfo.setId(dbUserInfo.getId());
        userInfo.setPassword(null);
        updateUserLoginInfo(userInfo);
        return token;
    }
    //异步执行：  this调用自己的方法不会被动态代理 aop会失效，调用方法时必须装配容器中被代理过的对象才可以
    @Async
    @Override
    public void updateUserLoginInfo(UserInfo userInfo) {
        this.updateById(userInfo);
    }

    @Override
    public UserInfoVo getCurrentUserInfo(String token) {
//        UserInfo  userInfo = (UserInfo) redisTemplate.opsForValue().get("spzx:user:login:" + token);
//        if(userInfo==null){
//            //登录状态失效
//            throw new SpzxException(ResultCodeEnum.LOGIN_STATUS_ERROR,null);
//        }
        UserInfo  userInfo = SpzxServiceAuthInterceptor.THREAD_LOCAL.get();
        UserInfoVo userInfoVo = new UserInfoVo();
        userInfoVo.setNickName(userInfo.getNickName());
        userInfoVo.setAvatar(userInfo.getAvatar());
        return userInfoVo;
    }
}
